﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DiscoveryLogic.Analytics.BusinessLogic.Rules;
using DiscoveryLogic.Analytics.DataObjects;
using DiscoveryLogic.Analytics.DataObjects.Dedup;
using DiscoveryLogic.Analytics.DataObjects.Networks;
using DiscoveryLogic.Analytics.DataObjects.Rules;
using DiscoveryLogic.Analytics.DataObjects.Visuals;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.Analytics.BusinessLogic.Dedups
{
    public class NetworkDedupWorker
    {
        private Network _Network;
        private Dictionary<EntityType, EntityDedupRule> _DedupRules;

        public NetworkDedupWorker(string networkName)
        {
            this._Network = Network.Read(networkName);
            NetworkDedupSetting netDedupSetting = NetworkDedupSetting.Read(networkName);
            this._DedupRules=new Dictionary<EntityType, EntityDedupRule>();
            List<RuleBase> dedupRules = RuleManager.GetRulesByType(RuleType.Dedup, EntityIcons.DedupRuleIcon);
            foreach(EntityType entityType in netDedupSetting.DedupRules.Keys)
            {
                string ruleName = netDedupSetting.DedupRules[entityType];
                foreach(RuleBase rule in dedupRules)
                {
                    if(rule.RuleName==ruleName)
                    {
                        this._DedupRules.Add(entityType,rule as EntityDedupRule);
                        break;
                    }
                }
            }
        }

        public NetworkDedupWorker(Network network, NetworkDedupSetting dedupSetting)
        {
            this._Network = network;
            this._DedupRules = new Dictionary<EntityType, EntityDedupRule>();
            List<RuleBase> dedupRules = RuleManager.GetRulesByType(RuleType.Dedup, EntityIcons.DedupRuleIcon);
            foreach (EntityType entityType in dedupSetting.DedupRules.Keys)
            {
                string ruleName = dedupSetting.DedupRules[entityType];
                foreach (RuleBase rule in dedupRules)
                {
                    if (rule.RuleName == ruleName)
                    {
                        this._DedupRules.Add(entityType, rule as EntityDedupRule);
                        break;
                    }
                }
            }
        }

        public Network DedupNetwork()
        {
            foreach(EntityType entityType in this._DedupRules.Keys)
            {
                Type type = EntityTypeUtil.GetType(entityType);
                
                EntityDedupWorker worker=new EntityDedupWorker(this._DedupRules[entityType]);
                List<EntityBase> entities=new List<EntityBase>();
                foreach(EntityBase entity in this._Network.Records)
                {
                    if(entity.EntityType==entityType)
                    {
                        entities.Add(entity);
                    }
                }
                Dictionary<string, List<string>> collapsedKeyMappings =
                    worker.DedupEntities(entities);
                Dictionary<string, string> keyToCollapsedKeys = new Dictionary<string, string>();
                int collapsedID = 0;
                foreach(string ck in collapsedKeyMappings.Keys)
                {
                    collapsedID++;
                    foreach(string key in collapsedKeyMappings[ck])
                    {
                        keyToCollapsedKeys.Add(key, ck);
                        foreach(EntityBase entity in entities)
                        {
                            if (entity.PKValue() == key)
                                entity.CollapsedID = collapsedID;
                        }
                    }
                }
                foreach(string key in keyToCollapsedKeys.Keys)
                {
                    foreach(Link link in this._Network.Links)
                    {
                        if (link.FromType == type && 
                            link.FromKey==key)
                            link.FromKey = keyToCollapsedKeys[key];
                        if (link.ToType == type && 
                            link.ToKey==key)
                            link.ToKey = keyToCollapsedKeys[key];
                    }
                }
                int idx = 0;
                while(idx<this._Network.Records.Count)
                {
                    if (this._Network.Records[idx].EntityType == entityType &&
                       !collapsedKeyMappings.ContainsKey(this._Network.Records[idx].PKValue()))
                    {
                        this._Network.Records.RemoveAt(idx);
                    }
                    else
                        idx++;
                }
            }

            return this._Network;
        }
    }
}
